/*	Interactive Gravitational Simulator
	Project: IGS Core
	File: Tensor.h
	Author: Mike Bantegui <mbante2@gmail.com>, Hofstra University 
	Copyright (C) 2012 - 2013 Mike Bantegui

	This file is part of the IGS software package for simulating
	the N-Body problem in real-time. This was developed as part
	of a departmental honors thesis project at Hofstra University
	in the Spring 2012 semester.

	IGS is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	IGS is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef IGS_TENSOR_H
#define IGS_TENSOR_H

#include "Vector.h"

namespace IGS
{

template <int N>
struct Tensor
{
	Tensor<N - 1> x;
	Tensor<N - 1> y;
	Tensor<N - 1> z;

	Tensor() {}

	Tensor(Tensor<N-1> x, Tensor<N-1> y, Tensor<N-1> z) : x(x), y(y), z(z) {}

	Tensor<N - 1> &operator[](int i) { return (&x)[i]; }
	const Tensor<N - 1> &operator[](int i) const { return (&x)[i]; }

	Tensor<N> &operator+=(const Tensor<N> &rhs)
	{
		x += rhs.x;
		y += rhs.y;
		z += rhs.z;
		return *this;
	}

	void Zero()
	{
		x.Zero();
		y.Zero();
		z.Zero();
	}

	double Sum(Tensor<N> other) const
	{
		return x.Sum(other.x) +
			y.Sum(other.y) +
			z.Sum(other.z);
	}
};

template <int M>
Tensor<M> operator-(const Tensor<M> &lhs, const Tensor<M> &rhs)
{
	Tensor<M> result;

	result.x = lhs.x - rhs.x;
	result.y = lhs.y - rhs.y;
	result.z = lhs.z - rhs.z;

	return result;
}

template <>
struct Tensor<1> : public Vector
{
	double Sum(Tensor<1> other) const
	{
		return Dot(*this, other);
	}

	Tensor() {}

	Tensor(const Vector &v) : Vector(v.x, v.y, v.z) {}

	Tensor(const double x, const double y, const double z) : Vector(x, y, z) {}

};

}

#endif